package handler

import (
	"cashcenter/internal/discovery"
	"cashcenter/internal/model"
	ctpAlipay "cashcenter/internal/pay/alipay"
	"cashcenter/internal/queue"
	"cashcenter/internal/service"
	"cashcenter/utils/errx"
	"cashcenter/utils/logx"
	"cashcenter/utils/resx"
	"cashcenter/utils/secret"
	"github.com/gin-gonic/gin"
	"strconv"
)

func CashIn(ctx *gin.Context) {
	claims, err := secret.GetJwtClaims(ctx.GetHeader("Authorization"))
	if err != nil {
		ctx.JSON(200, resx.GinResp(resx.AuthUnsupported, nil))
		return
	}
	var data CashInRequest
	err = ctx.BindJSON(&data)
	if err != nil {
		ctx.JSON(200, resx.GinResp(resx.BadRequest, nil))
		return
	}
	uuid := secret.GenerateUUID()
	err = model.InsertCashIn(&model.CashIn{
		InId:   uuid,
		UserId: claims.UserId,
		Count:  data.Count,
		State:  "unpaid",
	})
	if err != nil {
		ctx.JSON(200, resx.GinResp(resx.SystemErr, nil))
		return
	}
	// TODO 缓存订单

	err = queue.PubInClose(uuid)
	if err != nil {
		ctx.JSON(200, resx.GinResp(resx.SystemErr, nil))
		return
	}

	ctx.JSON(200, resx.GinResp(resx.Success, uuid))
	return
}

func CashOut(ctx *gin.Context) {
	claims, err := secret.GetJwtClaims(ctx.GetHeader("Authorization"))
	if err != nil {
		ctx.JSON(200, resx.GinResp(resx.AuthUnsupported, nil))
		return
	}
	var data CashOutRequest
	err = ctx.BindJSON(&data)
	if err != nil {
		ctx.JSON(200, resx.GinResp(resx.BadRequest, nil))
		return
	}

	// CoDeny
	_, err = model.InsertAccount(claims.UserId, -data.Count)
	if err != nil {
		if err == errx.CtpError(errx.DecError) {
			ctx.JSON(200, resx.GinResp(resx.Fail, "余额不足"))
			return
		}
		ctx.JSON(200, resx.GinResp(resx.SystemErr, err))
		return
	}

	// 生成提现单
	uuid := secret.GenerateUUID()
	err = model.InsertCashOut(&model.CashOut{
		OutId:  uuid,
		UserId: claims.UserId,
		Count:  data.Count,
		State:  "review",
	})
	if err != nil {
		ctx.JSON(200, resx.GinResp(resx.SystemErr, nil))
		return
	}

	// 发送提醒邮件（成败随意）
	//emailService := ctx.Keys["email"].(service.EmailServiceClient)
	//_, _ = emailService.EmailRemind(ctx, &service.EmailRemindRequest{
	//	Email:   claims.Email,
	//	Content: "您的账号正在发起提现，单号：" + uuid,
	//})
	emailConn := discovery.EmailDiscover.Get()
	if emailConn == nil {
		logx.LogrusObj.Warning("[API]:", errx.CtpError(errx.RpcError))
		ctx.JSON(200, resx.GinResp(resx.Success, uuid))
		return
	}
	emailServiceClient := service.NewEmailServiceClient(emailConn)
	rpcResp, err := emailServiceClient.EmailRemind(ctx, &service.EmailRemindRequest{
		Email:   claims.Email,
		Content: "您的账号正在发起提现，单号：" + uuid,
	})
	if rpcResp.GetCode() == 14 {
		discovery.EmailDiscover.Sad(emailConn.Target())
	}

	ctx.JSON(200, resx.GinResp(resx.Success, uuid))
	return
}

func Balance(ctx *gin.Context) {
	claims, err := secret.GetJwtClaims(ctx.Request.Header.Get("Authorization"))
	if err != nil {
		ctx.JSON(200, resx.GinResp(resx.SystemErr, err))
		return
	}

	account := model.QueryLastAccount(claims.UserId)

	ctx.JSON(200, resx.GinResp(resx.Success, account.Balance))
	return
}

func Account(ctx *gin.Context) {
	claims, err := secret.GetJwtClaims(ctx.Request.Header.Get("Authorization"))
	if err != nil {
		ctx.JSON(200, resx.GinResp(resx.SystemErr, err))
		return
	}

	accounts := model.QueryAccounts(claims.UserId)

	ctx.JSON(200, resx.GinResp(resx.Success, resx.DataList{
		Items: accounts,
		Total: len(*accounts),
	}))
	return
}

func AlipayPage(ctx *gin.Context) {
	uuid := ctx.Query("key")
	if uuid == "" {
		ctx.JSON(200, resx.GinResp(resx.BadRequest, nil))
		return
	}
	cashinInfo := model.QueryCashInByInId(uuid)
	if cashinInfo.InId == "" {
		ctx.JSON(200, resx.GinResp(resx.NilResult, nil))
		return
	}
	if cashinInfo.State == "closed" {
		ctx.JSON(200, resx.GinResp(resx.DealExpire, nil))
		return
	}

	// TODO 缓存订单状态、类型、值
	strF := strconv.FormatFloat(float64(cashinInfo.Count)/100, 'f', 2, 64)
	payUrl, err := ctpAlipay.GetPayPage("CTP充值", uuid, strF)
	if err != nil {
		ctx.JSON(200, resx.GinResp(resx.BadRequest, nil))
		return
	}

	ctx.JSON(200, resx.GinResp(resx.Success, payUrl))
	return
}

// TODO make cache
// TODO timer work

func AlipayNotify(ctx *gin.Context) {
	// 获取 notify 信息
	noti, err := ctpAlipay.AlipayClient.GetTradeNotification(ctx.Request)
	if err != nil {
		ctx.JSON(200, resx.GinResp(resx.SystemErr, err))
		return
	}

	// 更新支付状态
	err = model.UpdateCashIn(&model.CashIn{
		State: "paid",
		InId:  noti.OutTradeNo,
	})
	if err != nil {
		ctx.JSON(200, resx.GinResp(resx.SystemErr, err))
		return
	}

	// 获取充值信息
	cashinInfo := model.QueryCashInByInId(noti.OutTradeNo)

	// 获取金额-int64
	dValueF, err := strconv.ParseFloat(noti.TotalAmount, 64)
	if err != nil {
		ctx.JSON(200, resx.GinResp(resx.SystemErr, err))
		return
	}
	dValue := int64(dValueF * 100)

	// 插入流水账
	_, err = model.InsertAccount(cashinInfo.UserId, dValue)
	if err != nil {
		ctx.JSON(200, resx.GinResp(resx.SystemErr, err))
		return
	}
	ctx.JSON(200, resx.GinResp(resx.Success, nil))
	return
}

func AlipayReturn(ctx *gin.Context) {
	// TODO page turn
	ctx.Redirect(301, "http://47.111.152.148:30501/ctp/front/MainPage/UserAccount")
}

func AlipayState(ctx *gin.Context) {
	uuid := ctx.Query("uuid")

	cashInInfo := model.QueryCashInByInId(uuid)

	ctx.JSON(200, resx.GinResp(resx.Success, cashInInfo.State))
	return
}

type CashInRequest struct {
	Count int64 `json:"count" binding:"required"`
}

type CashOutRequest struct {
	Count int64 `json:"count" binding:"required"`
}

// 管理

func CoList(ctx *gin.Context) {
	stat := ctx.DefaultQuery("stat", "review")
	part := ctx.DefaultQuery("part", "1")
	if part == "0" {
		coList := model.QueryCashOutList(stat, part, 0, 0)
		ctx.JSON(200, resx.GinResp(resx.Success, resx.DataList{
			Items: *coList,
			Total: len(*coList),
		}))
		return
	}

	page := ctx.DefaultQuery("page", "1")
	pmax := ctx.DefaultQuery("pmax", "6")

	pageInt, err1 := strconv.Atoi(page)
	pmaxInt, err2 := strconv.Atoi(pmax)
	if err1 != nil || err2 != nil {
		ctx.JSON(200, resx.GinResp(resx.BadRequest, nil))
	}
	offset := (pageInt - 1) * pmaxInt
	count, err := model.QueryCashOutCount(stat)
	if err != nil {
		ctx.JSON(200, resx.GinResp(resx.SystemErr, err))
		return
	}
	if count <= int64(offset) {
		ctx.JSON(200, resx.GinResp(resx.OutOfRange, &gin.H{"last": count/int64(pmaxInt) + 1}))
		return
	}

	coList := model.QueryCashOutList(stat, part, offset, pmaxInt)
	ctx.JSON(200, resx.GinResp(resx.Success, &resx.DataList{
		Items:    *coList,
		Total:    len(*coList),
		LastPage: count/int64(pmaxInt) + 1,
	}))
	return
}

func CoAudit(ctx *gin.Context) {
	req := AuditRequest{}
	err := ctx.BindJSON(&req)
	if err != nil {
		ctx.JSON(200, resx.GinResp(resx.BadRequest, nil))
		return
	}

	cashOutInfo := model.QueryCashOutByUuid(req.OutId)
	if cashOutInfo.State != "review" {
		ctx.JSON(200, resx.GinResp(resx.Fail, nil))
		return
	}

	err = model.UpdateCashOut(&model.CashOut{
		State: req.Result,
		OutId: req.OutId,
	})
	if err != nil {
		ctx.JSON(200, resx.GinResp(resx.SystemErr, err))
		return
	}

	if req.Result == "deny" {
		_, err := model.InsertAccount(cashOutInfo.UserId, cashOutInfo.Count)
		if err != nil {
			ctx.JSON(200, resx.GinResp(resx.SystemErr, err))
			return
		}
	} else if req.Result == "allow" {
		// TODO 提现到账现实逻辑
	}

	ctx.JSON(200, resx.GinResp(resx.Success, nil))
	return
}

type AuditRequest struct {
	OutId  string `json:"outId"`
	Result string `json:"result"`
}
